﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BackEnd.Facade.Interfaces;
using BackEnd.Integration;


namespace BackEnd.Facade.Implementations
{
    public class TaxiServiceManager : ITaxiServiceManager
    {

        #region ITaxiServiceManager Members

        public List<Domain.TaxiService> GetAllServices()
        {
            using (var ctx = new TaxiDataDataContext())
            {
                ctx.ObjectTrackingEnabled = false;
                var list = (from s in ctx.TaxiServices
                           select new Domain.TaxiService()
                           {
                               Id = s.TaxiServiceId,
                               NameAM = s.NameAM,
                               NameEN = s.NameEN,
                               NameRU = s.NameRU,
                               DescriptionAM = s.DescriptionAM,
                               DescriptionEN = s.DescriptionEN,
                               DescriptionRU = s.DescriptionRU,
                               
                               Status = new Domain.ServiceStatus() { Code = s.StatusCode },

                               //Options
                               Conditioning = s.Conditioning,
                               HasMeter = s.HasMeter,
                               NoSmoking = s.NoSmoking,
                               SpeaksEnglish = s.SpeaksEnglish,
                               //Price policy
                               PricePolicy = new Domain.PricePolicy()
                               {
                                   MinPrice = s.MinPrice,
                                   PricePerKM = s.PricePerKM,
                                   MinPriceKM = s.MinPriceKM,
                                   FreeWaitMinutes = s.FreeWaitMinutes,
                                   WaitMinutePrice = s.WaitMinutePrice,
                                   UpTo6KMPrice = s.UpToSixKMPrice,
                                   OutsideTownPrice = s.OutsideTownKMPrice,
                                   ToAirportPrice = s.AirportPrice
                               },

                               CreateDate = s.CreateDate,
                               ViewCount = s.ViewCount,
                               ParkQuantity = s.ParkQuantity,
                               InternalNotes =s.Notes,
                               
                               Contacts = new Domain.ContactInfo() 
                               { 
                                   PhoneNumber =s.PhoneNumber,
                                   PhoneNumber1 = s.PhoneNumber1,
                                   PhoneNumber2 = s.PhoneNumber2,
                                   PhoneNumber3 = s.PhoneNumber3,
                                   PhoneNumber4 = s.PhoneNumber4,
                               }, 
                               District = s.DistrictId.HasValue ? new Domain.District(){Id = s.DistrictId.Value} : null
                           }).ToList();
                return list;
            }
        }


        public int CreateService(Domain.TaxiService service)
        {
            using (var ctx = new TaxiDataDataContext())
            {
                TaxiService entity = new TaxiService()
                {
                    NameAM = service.NameAM,
                    NameEN = service.NameEN,
                    NameRU = service.NameRU,
                    DescriptionAM = service.DescriptionAM,
                    DescriptionRU = service.DescriptionRU,
                    DescriptionEN = service.DescriptionEN,
                    

                    PhoneNumber = service.Contacts.PhoneNumber,
                    PhoneNumber1 = service.Contacts.PhoneNumber1,
                    PhoneNumber2 = service.Contacts.PhoneNumber2,
                    PhoneNumber3 = service.Contacts.PhoneNumber3,
                    PhoneNumber4 = service.Contacts.PhoneNumber4,
                    StatusCode = "PE",

                    
                    //Price policy
                    PricePerKM = service.PricePolicy.PricePerKM,
                    MinPrice = service.PricePolicy.MinPrice,
                    MinPriceKM = service.PricePolicy.MinPriceKM,
                    UpToSixKMPrice = service.PricePolicy.UpTo6KMPrice,
                    AirportPrice = service.PricePolicy.ToAirportPrice,
                    OutsideTownKMPrice = service.PricePolicy.OutsideTownPrice,
                    WaitMinutePrice = service.PricePolicy.WaitMinutePrice,
                    FreeWaitMinutes = service.PricePolicy.FreeWaitMinutes,

                    ParkQuantity = service.ParkQuantity,
                    ServingFromYear = service.ServingFromYear,
                    CreateDate = DateTime.Now,
                    Notes = service.InternalNotes,

                    //Avarage Rating
                    AvgCarRating = 0,
                    AvgDriverRating = 0,
                    AvgPriceRating = 0,
                    AvgRating = 0,
                    AvgServiceRating = 0,
                    
                    //Options
                    HasMeter = service.HasMeter,
                    Conditioning = service.Conditioning,
                    NoSmoking = service.NoSmoking,
                    SpeaksEnglish = service.SpeaksEnglish,

                    ViewCount = 0,
                    DistrictId = service.District != null ? service.District.Id : (short?)null
                };

                foreach (var transport in service.Transports)
                {
                    entity.ServiceTransports.Add(new ServiceTransport()
                    {
                        CarId = transport.Car.Id,
                        CreateDate = DateTime.Now,
                        Quantity = transport.Quantity,
                        PricePerKM = transport.SpecialPricePolicy != null ? transport.SpecialPricePolicy.PricePerKM : (short?)null,
                        UpToSixKMPrice = transport.SpecialPricePolicy != null ? transport.SpecialPricePolicy.UpTo6KMPrice : (short?)null,
                        MinPrice = transport.SpecialPricePolicy != null ? transport.SpecialPricePolicy.MinPrice : (short?)null,
                    });
                }

                ctx.TaxiServices.InsertOnSubmit(entity);
                ctx.SubmitChanges();
                return entity.TaxiServiceId;
            }
            
            
        }

        public List<Domain.District> GetAllDistricts()
        {
            using (var ctx = new TaxiDataDataContext())
            {
                ctx.ObjectTrackingEnabled = false;
                return (from dist in ctx.Districts
                        select new Domain.District()
                        {
                            Id = dist.DistrictId,
                            NameAM = dist.NameAM,
                            NameEN = dist.NameEN,
                            NameRU = dist.NameRU
                        }).ToList();
            }
        }

        public List<Domain.Car> GetAllCars()
        {
            using (var ctx = new TaxiDataDataContext())
            {
                ctx.ObjectTrackingEnabled = false;
                return (from car in ctx.Cars
                        select new Domain.Car()
                        {
                            Id = car.CarId,
                            Make = car.Make,
                            Model = car.Model,
                            Year = car.Year,
                            MaxPassenger = car.MaxPassenger,
                            CreateDate = car.CreateDate,
                            Class = car.Class,
                            Type = new Domain.TransportType() { Code = car.TypeCode }
                        }).ToList();
            }
        }

        public List<Domain.TaxiService> GetTopTaxisByDistrict(Domain.TaxiSortBy sortBy, int count, short districtId)
        {
            using (var ctx = new TaxiDataDataContext())
            {
                ctx.ObjectTrackingEnabled = false;
                IQueryable<TaxiService> queryable = null;

                switch (sortBy)
                {
                    case Domain.TaxiSortBy.Cheapest:
                        queryable = ctx.TaxiServices.OrderBy(m => m.PricePerKM)
                                                    .OrderBy(m => m.UpToSixKMPrice)
                                                    .OrderBy(m => m.MinPrice)
                                                    .OrderByDescending(m => m.FreeWaitMinutes)
                                                    .OrderBy(m => m.WaitMinutePrice)
                                                    .OrderBy(m => m.AirportPrice)
                                                    .OrderBy(m => m.OutsideTownKMPrice)
                                                    .OrderByDescending(m => m.AvgPriceRating);
                        break;
                    case Domain.TaxiSortBy.Popular:
                        queryable = ctx.TaxiServices.OrderByDescending(m => m.ViewCount)
                                                    .OrderByDescending(m => m.CustomerFeedbacks.Count)
                                                    .OrderByDescending(m => m.AvgRating);
                        break;
                    case Domain.TaxiSortBy.HighestRating:
                        queryable = ctx.TaxiServices.OrderByDescending(m => m.AvgRating)
                                                    .OrderByDescending(m => m.CustomerFeedbacks.Count)
                                                    .OrderByDescending(m => m.AvgServiceRating)
                                                    .OrderByDescending(m => m.AvgPriceRating)
                                                    .OrderByDescending(m => m.AvgCarRating)
                                                    .OrderByDescending(m => m.AvgDriverRating);
                        break;
                    case Domain.TaxiSortBy.Comfortable:
                        queryable = ctx.TaxiServices.OrderByDescending(m => m.ServiceTransports.Average(s => s.Car.Class))
                                                    .OrderByDescending(m => m.AvgCarRating)
                                                    .OrderByDescending(m => m.AvgDriverRating)
                                                    .OrderByDescending(m => m.AvgServiceRating)
                                                    .OrderByDescending(m => m.AvgPriceRating)
                                                    .OrderByDescending(m => m.AvgDriverRating);
                        break;
                }

                var result = (from s in queryable
                              where s.DistrictId == districtId
                              select new Domain.TaxiService()
                              {
                                  Id = s.TaxiServiceId,
                                  NameAM = s.NameAM,
                                  NameEN = s.NameEN,
                                  NameRU = s.NameRU,
                                  Conditioning = s.Conditioning,
                                  HasMeter = s.HasMeter,
                                  NoSmoking = s.NoSmoking,
                                  SpeaksEnglish = s.SpeaksEnglish,

                                  PricePolicy = new Domain.PricePolicy()
                                  {
                                      MinPrice = s.MinPrice,
                                      PricePerKM = s.PricePerKM,
                                      WaitMinutePrice = s.WaitMinutePrice,
                                      MinPriceKM = s.MinPriceKM,
                                      FreeWaitMinutes = s.FreeWaitMinutes,
                                      UpTo6KMPrice = s.UpToSixKMPrice,
                                      ToAirportPrice = s.AirportPrice,
                                      OutsideTownPrice = s.OutsideTownKMPrice,
                                  },
                                  CreateDate = s.CreateDate,
                                  Contacts = new Domain.ContactInfo()
                                  {
                                      PhoneNumber = s.PhoneNumber
                                  },
                                  District = s.DistrictId.HasValue ? new Domain.District() { Id = s.DistrictId.Value } : null,
                                  AvgRating = s.AvgRating,
                                  ReviewsCount = s.CustomerFeedbacks.Count,
                                  ParkQuantity = s.ParkQuantity,



                              }).Take(count).ToList();

                return result;
            }
        }

        public List<Domain.TaxiService> GetTopTaxis(Domain.TaxiSortBy sortBy, int count)
        {
            using (var ctx = new TaxiDataDataContext())
            {
                ctx.ObjectTrackingEnabled = false;
                IQueryable<TaxiService> queryable = null;
                
                switch (sortBy)
                {
                    case Domain.TaxiSortBy.Cheapest:
                        queryable = ctx.TaxiServices.OrderBy(m => m.PricePerKM)
                                                    .OrderBy(m => m.UpToSixKMPrice)
                                                    .OrderBy(m => m.MinPrice)
                                                    .OrderByDescending(m => m.FreeWaitMinutes)
                                                    .OrderBy(m => m.WaitMinutePrice)
                                                    .OrderBy(m => m.AirportPrice)
                                                    .OrderBy(m => m.OutsideTownKMPrice)
                                                    .OrderByDescending(m => m.AvgPriceRating);
                        break;
                    case Domain.TaxiSortBy.Popular:
                        queryable = ctx.TaxiServices.OrderByDescending(m => m.ViewCount)
                                                    .OrderByDescending(m => m.CustomerFeedbacks.Count)
                                                    .OrderByDescending(m => m.AvgRating);
                        break;
                    case Domain.TaxiSortBy.HighestRating:
                        queryable = ctx.TaxiServices.OrderByDescending(m => m.AvgRating)
                                                    .OrderByDescending(m => m.CustomerFeedbacks.Count)
                                                    .OrderByDescending(m => m.AvgServiceRating)
                                                    .OrderByDescending(m => m.AvgPriceRating)
                                                    .OrderByDescending(m => m.AvgCarRating)
                                                    .OrderByDescending(m => m.AvgDriverRating);
                        break;
                    case Domain.TaxiSortBy.Comfortable:
                        queryable = ctx.TaxiServices.OrderByDescending(m => m.ServiceTransports.Average(s => s.Car.Class))
                                                    .OrderByDescending(m => m.AvgCarRating)
                                                    .OrderByDescending(m => m.AvgDriverRating)
                                                    .OrderByDescending(m => m.AvgServiceRating)
                                                    .OrderByDescending(m => m.AvgPriceRating)
                                                    .OrderByDescending(m => m.AvgDriverRating);
                        break;
                }

                var result = (from s in queryable
                              select new Domain.TaxiService()
                              {
                                  Id = s.TaxiServiceId,
                                  NameAM = s.NameAM,
                                  NameEN = s.NameEN,
                                  NameRU = s.NameRU,
                                  Conditioning = s.Conditioning,
                                  HasMeter = s.HasMeter,
                                  NoSmoking = s.NoSmoking,
                                  SpeaksEnglish = s.SpeaksEnglish,

                                  PricePolicy = new Domain.PricePolicy()
                                  {
                                      MinPrice = s.MinPrice,
                                      PricePerKM = s.PricePerKM,
                                      WaitMinutePrice = s.WaitMinutePrice,
                                      MinPriceKM = s.MinPriceKM,
                                      FreeWaitMinutes = s.FreeWaitMinutes,
                                      UpTo6KMPrice = s.UpToSixKMPrice,
                                      ToAirportPrice = s.AirportPrice,
                                      OutsideTownPrice = s.OutsideTownKMPrice,
                                  },
                                  CreateDate = s.CreateDate,
                                  Contacts = new Domain.ContactInfo()
                                  {
                                      PhoneNumber = s.PhoneNumber
                                  },
                                  District = s.DistrictId.HasValue ? new Domain.District() { Id = s.DistrictId.Value } : null,
                                  AvgRating = s.AvgRating,
                                  ReviewsCount = s.CustomerFeedbacks.Count,
                                  ParkQuantity = s.ParkQuantity,



                              }).Take(count).ToList();

                return result;
            }
        }

        public Domain.TaxiService GetTaxiServiceById(int id)
        {
            using(var ctx = new TaxiDataDataContext())
            {
                var entity = (from s in ctx.TaxiServices where s.TaxiServiceId == id select s).Single();

                entity.ViewCount++;
                ctx.SubmitChanges();

                //ctx.ObjectTrackingEnabled = false;
                var service = (from s in ctx.TaxiServices
                               where s.TaxiServiceId == id
                               select new Domain.TaxiService()
                               {
                                   Id = s.TaxiServiceId,
                                   NameAM = s.NameAM,
                                   NameEN = s.NameEN,
                                   NameRU = s.NameRU,
                                   DescriptionAM = s.DescriptionAM,
                                   DescriptionEN = s.DescriptionEN,
                                   DescriptionRU = s.DescriptionRU,
                                   Status = new Domain.ServiceStatus() { Code = s.StatusCode },

                                   //Options
                                   Conditioning = s.Conditioning,
                                   HasMeter = s.HasMeter,
                                   NoSmoking = s.NoSmoking,
                                   SpeaksEnglish = s.SpeaksEnglish,
                                   //Price policy
                                   PricePolicy = new Domain.PricePolicy()
                                   {
                                       MinPrice = s.MinPrice,
                                       PricePerKM = s.PricePerKM,
                                       WaitMinutePrice = s.WaitMinutePrice,
                                       MinPriceKM = s.MinPriceKM,
                                       FreeWaitMinutes = s.FreeWaitMinutes,
                                       UpTo6KMPrice = s.UpToSixKMPrice,
                                       ToAirportPrice = s.AirportPrice,
                                       OutsideTownPrice = s.OutsideTownKMPrice,
                                   },

                                   CreateDate = s.CreateDate,
                                   ViewCount = s.ViewCount,
                                   ReviewsCount = s.CustomerFeedbacks.Count,
                                   ServingFromYear = s.ServingFromYear,

                                   ParkQuantity = s.ParkQuantity,
                                   InternalNotes = s.Notes,
                                   
                                   Contacts = new Domain.ContactInfo()
                                   {
                                       PhoneNumber = s.PhoneNumber,
                                       PhoneNumber1 = s.PhoneNumber1,
                                       PhoneNumber2 = s.PhoneNumber2,
                                       PhoneNumber3 = s.PhoneNumber3,
                                       PhoneNumber4 = s.PhoneNumber4,
                                   },
                                   AvgRating = s.AvgRating,
                                   AvgCarRating = s.AvgCarRating,
                                   AvgPriceRating = s.AvgPriceRating,
                                   AvgDriverRating = s.AvgDriverRating,
                                   AvgServiceRating = s.AvgServiceRating,
                                   
                                   
                                   District = s.DistrictId.HasValue ? new Domain.District() { 
                                       Id = s.DistrictId.Value, 
                                       NameAM = s.District.NameAM,
                                       NameEN = s.District.NameEN,
                                       NameRU = s.District.NameRU } : null
                               }).Single();

                var transports = (from t in ctx.ServiceTransports
                                  where t.TaxiServiceId == id
                                  select new Domain.ServiceTransport()
                                  {
                                      Car = new Domain.Car()
                                      {
                                          Id = t.Car.CarId,
                                          Make = t.Car.Make,
                                          Model = t.Car.Model,
                                          Year = t.Car.Year,
                                          Type = new Domain.TransportType() { Code = t.Car.TypeCode },
                                          MaxPassenger = t.Car.MaxPassenger,
                                          Class = t.Car.Class,
                                          CreateDate = t.CreateDate
                                      },
                                      Quantity = t.Quantity,
                                      SpecialPricePolicy = t.MinPrice.HasValue ? new Domain.PricePolicy() {
                                          MinPrice = t.MinPrice.Value,
                                          PricePerKM = t.PricePerKM.Value,
                                          UpTo6KMPrice = t.UpToSixKMPrice,
                                      } : null ,
                                  }
                                  ).ToList();
                service.Transports = transports;
                return service;
            }
        }
        #endregion
    }
}
